<template>
  <a-row :gutter="gutter" wrap>
    <a-form
      ref="tableForm"
      class="table-form"
      :model="formModel"
      auto-label-width
      :layout="layout"
      @submit="handleSubmit"
    >
      <a-col
        v-for="(field, index) in visibleFields"
        :key="field.name"
        :data-index="field.index"
        :span="field.fieldProps.span ? field.fieldProps.span : 24"
        :class="{
          isDisplay: table && !collasp && index > 1,
        }"
      >
        <a-form-item
          :field="field.name"
          :label="field.label"
          :rules="field.rules"
          :tooltip="field.tooltip"
          :key="field.name + index"
        >
          <component
            v-if="field.type !== 'SelectIcon'"
            :is="field.type ? field.type : 'a-input'"
            v-model="formModel[field.name]"
            v-bind="field?.fieldProps"
            :placeholder="
              field.fieldProps.placeholder
                ? field.fieldProps.placeholder
                : '请输入'
            "
            @change="change"
          >
            <template v-if="field.type === 'a-select'">
              <template v-if="field.slotName === 'status'">
                <a-option
                  v-for="option in field.selectOptions"
                  :key="option.value"
                  :value="option.value"
                >
                  <a-badge :status="option.status" :text="option.label" />
                </a-option>
              </template>
              <template v-else>
                <a-option
                  v-for="(item, index) in field.selectOptions"
                  :key="index"
                  :value="
                    item[
                      field?.fieldProps?.fieldNames?.value
                        ? field?.fieldProps?.fieldNames?.value
                        : 'value'
                    ]
                  "
                >
                  {{
                    item[
                      field?.fieldProps?.fieldNames?.label
                        ? field?.fieldProps?.fieldNames?.label
                        : 'label'
                    ]
                  }}
                </a-option>
              </template>
            </template>
            <template
              v-if="field.checkboxOptions && field.type === 'a-checkbox-group'"
            >
              <a-checkbox
                v-for="item in field.checkboxOptions"
                :value="item.value"
                :key="item.label + index"
              >
                {{ item.label }}
              </a-checkbox>
            </template>
            <template v-if="field.type === 'a-radio-group'">
              <a-radio
                v-for="(item, index) in field.options"
                :key="item.label + index"
                :value="item.value"
                >{{ item.label }}</a-radio
              >
            </template>

            <template #upload-button v-if="field.type === 'a-upload'">
              <div
                :class="`arco-upload-list-item${
                  file && file.status === 'error'
                    ? ' arco-upload-list-item-error'
                    : ''
                }`"
              >
                <div
                  class="arco-upload-list-picture custom-upload-avatar"
                  v-if="file && file.url"
                >
                  <img :src="file.url" />
                  <div class="arco-upload-list-picture-mask">
                    <IconEdit />
                  </div>
                  <a-progress
                    v-if="file.status === 'uploading' && file.percent < 100"
                    :percent="file.percent"
                    type="circle"
                    size="mini"
                    :style="{
                      position: 'absolute',
                      left: '50%',
                      top: '50%',
                      transform: 'translateX(-50%) translateY(-50%)',
                    }"
                  />
                </div>
                <div class="arco-upload-picture-card" v-else>
                  <div class="arco-upload-picture-card-text">
                    <IconPlus />
                    <div style="margin-top: 10px; font-weight: 600">上传</div>
                  </div>
                </div>
              </div>
            </template>
          </component>
          <select-icon
            v-if="field.type === 'SelectIcon'"
            v-model:value="formModel[field.name]"
            :fieldProps="field.fieldProps"
            :placeholder="field.placeholder"
            @change="change"
          ></select-icon>
          <template #extra>
            <div>{{ field.extra }}</div>
          </template>
        </a-form-item>
      </a-col>
      <a-col
        :span="8"
        flex="1"
        style="text-align: right; margin-bottom: 20px; grid-column: 3 / span 1"
        v-if="table"
      >
        <a-button style="margin-right: 10px" @click="resetForm1">
          重置
        </a-button>
        <a-button
          html-type="submit"
          type="primary"
          :loading="loading"
          :disabled="isFormChanged"
        >
          查询
        </a-button>
        <span v-if="visibleFields.length > 2">
          <a-link
            v-if="!collasp"
            :hoverable="false"
            style="margin-left: 10px"
            @click="
              () => {
                collasp = true;
              }
            "
            >展开<icon-down style="margin-left: 10px"
          /></a-link>
          <a-link
            @click="
              () => {
                collasp = false;
              }
            "
            v-if="collasp"
            :hoverable="false"
            style="margin-left: 10px"
            >收缩<icon-up style="margin-left: 10px"
          /></a-link>
        </span>
      </a-col>
      <!--    普通表单  -->
      <a-form-item v-if="!table && showSubmit && !hiddenBtn">
        <a-button type="primary" html-type="submit" :disabled="isFormChanged">{{
          btnTitle[0]
        }}</a-button>
        <a-button style="margin-left: 10px !important" @click="resetForm">
          {{ btnTitle[1] ? btnTitle[1] : '重置' }}
        </a-button>
      </a-form-item>
    </a-form>
  </a-row>
</template>

<script lang="ts" setup>
  import { toRefs, ref, watch, computed, nextTick } from 'vue';
  import { FormInstance } from '@arco-design/web-vue';
  import { isEqual, cloneDeep } from 'lodash';

  defineOptions({
    name: 'ProForm',
  });
  const collasp = ref(false);
  const originalFormModel = ref({});
  const isFormChanged = ref(false);

  const props = withDefaults(
    defineProps<{
      formJson: Record<string, any>[];
      formData: any;
      layout?: 'horizontal' | 'vertical' | 'inline';
      labelAlign?: 'left' | 'right';
      gutter?: number;
      display?: boolean;
      table?: boolean;
      showSubmit?: boolean;
      loading?: boolean;
      btnTitle?: string[];
      hiddenBtn?: boolean;
    }>(),
    {
      gutter: 20,
      layout: 'horizontal',
      formJson: () => [],
      display: false,
      rules: () => [],
      formData: () => ({}),
      table: false,
      showSubmit: true,
      btnTitle: () => ['保存', '重置'],
      hiddenBtn: false,
    }
  );

  const emit = defineEmits([
    'update:loadingBtn',
    'search',
    'change',
    'resetForm',
    'formModelChange',
  ]);

  function resetForm1() {
    tableForm.value?.resetFields();
    emit('resetForm');
  }

  // ref绑定组件
  const tableForm = ref<FormInstance | null>(null);
  const formModel = ref({} as any);
  const { formJson, formData, layout, labelAlign, gutter } = toRefs(props);

  const checkForm = async () => {
    return await tableForm.value?.validate();
  };

  const visibleFields = computed(() => {
    if (!props.display) {
      return formJson?.value === undefined ? false : formJson.value;
    }
    return props?.display();
  }) as unknown as Array<any>;

  // 初始化原始数据
  watch(
    () => props.formData,
    (newVal) => {
      formModel.value = cloneDeep(newVal);
      originalFormModel.value = cloneDeep(newVal); // 同步更新原始数据
      isFormChanged.value = true;
    },
    { immediate: true, deep: true }
  );

  // 监听表单数据变化
  watch(
    () => formModel.value,
    (newVal, oldVal) => {
      isFormChanged.value = isEqual(formModel.value, originalFormModel.value);
      emit('formModelChange', newVal, oldVal);
    },
    { deep: true }
  );

  /*
   * 按 data-index 将组件进行排序
   **/
  nextTick(() => {
    const elements = document.querySelectorAll('.table-form .arco-col');
    const formBox = document.querySelector('.table-form');
    // 将 elements 转换为数组
    const elementsArray = Array.from(elements);
    // 按照 data-index 进行排序
    elementsArray.sort((a, b) => {
      const indexA = a.getAttribute('data-index');
      const indexB = b.getAttribute('data-index');
      return parseInt(indexA || '0') - parseInt(indexB || '0');
    });
    elementsArray.forEach((element) => {
      // 如果没有data-index则不需要
      if (!element.getAttribute('data-index')) return;
      // 将元素插入到 DOM 中
      formBox?.appendChild(element);
    });
  });

  const change = (val: any) => {
    emit('change', val);
  };

  const handleSubmit = async ({ values, errors }) => {
    if (errors || isFormChanged.value) {
      return false;
    }
    if (props.table) {
      emit('update:loadingBtn', true);
      try {
        await emit('search', cloneDeep(formModel.value));
      } finally {
        emit('update:loadingBtn', false);
      }
    } else {
      await emit('search', cloneDeep(formModel.value));
    }
  };

  const resetForm = () => {
    tableForm.value?.resetFields();
    formModel.value = cloneDeep(originalFormModel.value);
    isFormChanged.value = false;
  };

  defineExpose({
    formModel,
    tableForm,
    checkForm,
  });
</script>

<style scoped lang="less">
  .arco-btn {
    width: 80px;
  }
  .arco-col {
    text-align: center;
  }

  .arco-form {
    flex-direction: row !important;
    flex-wrap: wrap;
  }
  :deep(.arco-upload-wrapper) {
    width: 0px;
  }
  .isDisplay {
    display: none;
  }
  :deep(.icon) {
    width: 1.2em !important;
    height: 1.2em !important;
  }
</style>
